import Cesium from '../../Ces/Cesium'

function FlyingFlow(options) {
  this._width = 12;
  this._repeat = 64;
  this._speed = 0.01;
  this._reverse = false;
  this._rotateXY = true;

  this._positions = options.positions;
  this._clampToGround = options.clampToGround??false

  const url = options.flowImage;

  Cesium.Resource.fetchImage(url).then((image) => {
    this._image = image;
  });
}

Object.defineProperties(FlyingFlow.prototype, {
  width: {
    get() {
      return this._width;
    },
    set(value) {
      this._width = value;
    },
  },
  repeat: {
    get() {
      return this._repeat;
    },
    set(value) {
      this._repeat = value;
    },
  },
  speed: {
    get() {
      return this._speed;
    },
    set(value) {
      this._speed = value;
    },
  },
  reverse: {
    get() {
      return this._reverse;
    },
    set(value) {
      if (this._reverse !== value) {
        this._reverse = value;
      }
    },
  },
});


const shaderMovingTexture = `czm_material czm_getMaterial(czm_materialInput materialInput) {
    czm_material material = czm_getDefaultMaterial(materialInput);
    float iTime = czm_frameNumber / 60.0 * speed;
    vec2 st = materialInput.st;

    if(reverse){
        st.x = 1.0 - st.x;
    }

    st.x = fract(st.x - iTime);

    float scaledWidth = fract(repeat * st.x);
    scaledWidth = abs(scaledWidth - floor(scaledWidth));
    st.x = scaledWidth;

    vec2 uv = st;

    if(rotateXY){
        uv.x = st.y;
        uv.y = st.x;
    }

    vec4 color = texture(image, uv);
    material.diffuse = color.rgb;
    material.alpha = color.a;
    return material;
}`;

FlyingFlow.prototype.create = function (positions, image, context) {
  const width = this._width;

  const clampToGround = this._clampToGround;

  const instance = new Cesium.GeometryInstance({
    geometry: clampToGround ? new Cesium.GroundPolylineGeometry({
      positions,
      width,
    }) : new Cesium.PolylineGeometry({
      positions,
      width,
    }),
  });

  const texture = new Cesium.Texture({
    context,
    source: image,
  });

  const material = new Cesium.Material({
    fabric: {
      uniforms: {
        image: texture,
        repeat: this.repeat,
        speed: this.speed,
        reverse: this.reverse,
        rotateXY: this._rotateXY,
      },
      source: shaderMovingTexture,
    },
  });

  const appearance = new Cesium.PolylineMaterialAppearance({
    material,
  });

  const that = this;

  appearance.material._uniforms.speed_2 = function () {
    return that.speed;
  };
  appearance.material._uniforms.reverse_3 = function () {
    return that.reverse;
  };

  this._primitive = clampToGround ? new Cesium.GroundPolylinePrimitive({
    geometryInstances: instance,
    appearance,
    arcType: Cesium.ArcType.NONE,
  })
    : new Cesium.Primitive({
      geometryInstances: instance,
      appearance,
      arcType: Cesium.ArcType.NONE,
    });
};

FlyingFlow.prototype.destroy = function () {
  this._primitive = this._primitive && this._primitive.destroy();

  return Cesium.destroyObject(this);
};

FlyingFlow.prototype.isDestroyed = function () {
  return false;
};

FlyingFlow.prototype.update = function (frameState) {
  if (frameState.passes.render) {
    if (Cesium.defined(this._image)) {
      this.create(this._positions, this._image, frameState.context);
      this._image = undefined;
    }
    if (Cesium.defined(this._primitive)) {
      this._primitive.update(frameState);
    }
  }
};


export default FlyingFlow;
